import 'package:equatable/equatable.dart';
import 'package:im_app/im/util/ImCacheFactory.dart';
import 'package:im_app/im/util/ImSingleton.dart';

import '../../dao/ImCollectDao.dart';
import '../../pojo/Enums.dart';
import '../../pojo/ImPojo.dart';
import 'BaseBloc.dart';

final class CollectListCubit extends BaseBloc<CollectListEvent, CollectListState> {

  CollectListCubit() : super(CollectListState.loading()) {
    on<CollectListMessageTypeEvent>((event, emit) {
      _searchByMessageTypes(state, event.prefix, event.messageTypes);
    });
    on<CollectListCollectableEvent>((event, emit) {
      _collectable(state, event.collectable);
    });
    on<CollectListSearchEvent>((event, emit) {
      _search(state, event.search);
    });
    on<CollectListSearchKeyEvent>((event, emit) {
      _searchKeyEvent(state, event.search);
    });
    on<CollectListSearchableEvent>((event, emit) {
      _searchable(state, event.searchable);
    });
    on<CollectListLoadEvent>((event, emit) {
      _loadData(state);
    });
    on<CollectListCleanSearchEvent>((event, emit) {
      _cleanSearch(state);
    });
  }

  void _searchByMessageTypes(CollectListState oldState, String prefix, List<ImMessageType> messageTypes) async {
    var userId = ImSingleton.getInstance().session.userId!;
    var collects = await _doSearch(userId, oldState.search, messageTypes, 200);
    CollectListState newState = oldState.copy(messageTypes: messageTypes, collects: collects, prefix: prefix,
        collectable: false);
    emit(newState);
  }

  void _collectable(CollectListState oldState, bool collectable) {
    emit(oldState.copy(collectable: collectable));
  }

  void _search(CollectListState oldState, String search) async {
    var userId = ImSingleton.getInstance().session.userId!;
    var collects = await _doSearch(userId, search, oldState.messageTypes, 200);
    CollectListState newState = oldState.copy(search: search, collects: collects);
    emit(newState);
  }

  void _searchKeyEvent(CollectListState oldState, String search) async {
    CollectListState newState = oldState.copy(search: search);
    emit(newState);
  }

  void _searchable(CollectListState oldState, bool searchable) {
    emit(oldState.copy(searchable: searchable));
  }

  void _cleanSearch(CollectListState oldState) {
    var newState = oldState.copy(search: '');
    _loadData(newState);
  }

  void _loadData(CollectListState oldState) async {
    var userId = ImSingleton.getInstance().session.userId!;
    var collects = await _doSearch(userId, '', oldState.messageTypes, 200);
    CollectListState newState = oldState.copy(collects: collects);
    emit(newState);
  }

  Future<List<ImCollect>> _doSearch(String userId, String? search, List<ImMessageType> messageTypes, int pageSize) async {
    var collectDao = ImCollectDao();
    var collects = await collectDao.getCollects(userId, search, messageTypes, pageSize);
    for(var collect in collects) {
      collect.initContent();
      collect.message!.fromImUser = await ImCacheFactory.getInstance().getImUser(collect.message!.fromUserId);
    }
    return collects;
  }
}

final class CollectListState extends Equatable {

  final LoadingState state;
  final String prefix;
  final String search;
  final bool collectable;
  final bool searchable;
  final List<ImMessageType> messageTypes;
  final List<ImCollect> collects;

  const CollectListState._({
    this.state = LoadingState.loading,
    this.prefix = '',
    this.search = '',
    this.collectable = false,
    this.searchable = false,
    this.messageTypes = const <ImMessageType>[],
    this.collects = const <ImCollect>[],
  });

  CollectListState copy({String? prefix, String? search, List<ImMessageType>? messageTypes, bool? collectable,
    bool? searchable, LoadingState? state, List<ImCollect>? collects}) {
    return CollectListState._(
      state: state ?? this.state,
      prefix: prefix ?? this.prefix,
      search: search ?? this.search,
      collectable: collectable ?? this.collectable,
      searchable: searchable ?? this.searchable,
      messageTypes: messageTypes ?? this.messageTypes,
      collects: collects ?? this.collects,
    );
  }

  const CollectListState.loading() : this._();

  const CollectListState.success(List<ImCollect> collects)
      : this._(state: LoadingState.success, collects: collects);

  const CollectListState.failure() : this._(state: LoadingState.failure);

  @override
  List<Object?> get props => [state, prefix, search, collectable, searchable, messageTypes, collects];

}

class CollectListEvent {}
class CollectListMessageTypeEvent extends CollectListEvent {
  String prefix;
  List<ImMessageType> messageTypes;
  CollectListMessageTypeEvent(this.prefix, this.messageTypes);
}
class CollectListCollectableEvent extends CollectListEvent {
  bool collectable;
  CollectListCollectableEvent(this.collectable);
}
class CollectListSearchEvent extends CollectListEvent {
  String search;
  CollectListSearchEvent(this.search);
}
class CollectListSearchKeyEvent extends CollectListEvent {
  String search;
  CollectListSearchKeyEvent(this.search);
}
class CollectListSearchableEvent extends CollectListEvent {
  bool searchable;
  CollectListSearchableEvent(this.searchable);
}
class CollectListLoadEvent extends CollectListEvent {
  CollectListLoadEvent();
}
class CollectListCleanSearchEvent extends CollectListEvent {
  CollectListCleanSearchEvent();
}